package com.dream.xcarrecorder;

import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.ImageFormat;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.Image;
import android.media.ImageReader;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.util.Size;
import android.view.SurfaceHolder;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import com.dream.libxrec.utils.OsdHelper;
import com.dream.libxrec.view.YUVGLSurfaceView;
import com.dream.libxrec.view.YUVSurfaceViewRender;
import com.luoye.bzyuvlib.BZYUVUtil;
import java.util.Arrays;
import java.util.Date;
import java.util.Objects;

/**
 * Camera
 */
public class CameraPreviewActivity extends Activity {
    private Context mContext;
    private CameraDevice mCamera;
    private YUVGLSurfaceView mSurface;
    private final Handler mMainHandler = new Handler(Looper.getMainLooper());
    private final HandlerThread mEncoderThread = new HandlerThread(
            "EncoderThread");
    private Handler mEncoderHandler;
    private ImageReader mImageReader = null;//拍照用的类
    private static final String CAMERA_ID = "0";
    private static final int REQUEST_PERMISSION_CODE = 100;
    private final OsdHelper mOsdHelper = new OsdHelper(4,5);

    private final BZYUVUtil mBzyuvUtil = new BZYUVUtil();//libyuv封装库

    private final SurfaceHolder.Callback mSurfaceCb = new SurfaceHolder.Callback() {
        @Override
        public void surfaceCreated(@NonNull SurfaceHolder holder) {
            openCamera();
        }

        @Override
        public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {

        }

        @Override
        public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
            closeCamera();
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_preview);
        mContext = this;

        //申请动态权限
        if (ActivityCompat.checkSelfPermission(this,
                Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED){
            ActivityCompat.requestPermissions(
                    this,
                    new String[]{Manifest.permission.CAMERA},REQUEST_PERMISSION_CODE);
        }

        mSurface = findViewById(R.id.surface_view);
        mSurface.getHolder().addCallback(mSurfaceCb);

        initHandler();
    }

    private void initHandler() {
        mEncoderThread.start();
        mEncoderHandler = new Handler(mEncoderThread.getLooper());
    }

    private void openCamera(){
        if (ActivityCompat.checkSelfPermission(this,
                Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED){
            return;
        }

        CameraManager manager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);

        //初始化ImageReader，用于后续获取预览数据帧
        initImageReader(manager);

        try {
            manager.openCamera(CAMERA_ID, new CameraDevice.StateCallback() {
                @Override
                public void onOpened(@NonNull CameraDevice camera) {
                    mCamera = camera;
                    startPreview();
                }

                @Override
                public void onDisconnected(@NonNull CameraDevice camera) {

                }

                @Override
                public void onError(@NonNull CameraDevice camera, int error) {

                }
            }, mMainHandler);
        } catch (CameraAccessException e) {
            throw new RuntimeException(e);
        }
    }

    private void initImageReader(CameraManager manager) {
        try {
            CameraCharacteristics mCameraCharacteristics =
                    manager.getCameraCharacteristics(CAMERA_ID);
            StreamConfigurationMap map =
                    mCameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);

            if (map == null){
                return;
            }

            Size[] sizes =
                    map.getOutputSizes(SurfaceTexture.class);

            int width = sizes[0].getWidth();
            int height = sizes[0].getHeight();
            mOsdHelper.setLevelByImageSize(sizes[0]);
            //设置数据流分辨率
            mImageReader =
                    ImageReader.newInstance(width,height,
                            ImageFormat.YUV_420_888, 2);

            mSurface.init(
                    YUVSurfaceViewRender.RENDER_TYPE_NV12,width,height,
                    true);

            mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
                @Override
                public void onImageAvailable(ImageReader reader) {
                    synchronized (this){
                        Image image =  reader.acquireNextImage();

                        byte[] data =
                                mBzyuvUtil.preHandleYUV420(image,
                                        false, 0);

                        mOsdHelper.addYuvOsdText(data,width,height,
                                new Date().toGMTString(),5,5);

                        byte[] nv12 = new byte[data.length];
                        BZYUVUtil.yuvI420ToNV12(data,nv12,image.getWidth(),
                                    image.getHeight());

                        mSurface.onFrame(nv12);
                        image.close();
                    }
                }
            }, mEncoderHandler);

        }catch (Exception e){
            e.printStackTrace();
        }
    }


    private void closeCamera() {
        try {
            mCamera.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    private void startPreview() {
        try {
            mCamera.createCaptureSession(Arrays.asList(mImageReader.getSurface()), new CameraCaptureSession.StateCallback() {
                @Override
                public void onConfigured(@NonNull CameraCaptureSession session) {
                    try {
                        CaptureRequest.Builder captureRequestBuilder = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
                        captureRequestBuilder.addTarget(mImageReader.getSurface());
                        captureRequestBuilder.set(CaptureRequest.SENSOR_FRAME_DURATION, 1000000000L/15);
                        session.setRepeatingRequest(captureRequestBuilder.build(), null, mMainHandler);

                    } catch (CameraAccessException e) {
                        throw new RuntimeException(e);
                    }
                }

                @Override
                public void onConfigureFailed(@NonNull CameraCaptureSession session) {

                }
            }, mMainHandler);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode,
                                           @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions,
                grantResults);
        if (Objects.equals(permissions[0], Manifest.permission.CAMERA)){
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED){
                openCamera();
            }else{
                Toast.makeText(mContext, "已拒绝摄像头权限",
                        Toast.LENGTH_SHORT).show();
            }
        }
    }

    public static void startActivity(Context ct){
        Intent i = new Intent(ct, CameraPreviewActivity.class);
        ct.startActivity(i);
    }
}